/**
 * BGPKiller.java
 *
 * @author BJ Premore
 */


package SSF.OS.BGP4.Widgets;


import java.util.*;
import com.renesys.raceway.SSF.*;
import com.renesys.raceway.DML.*;
import SSF.Net.*;
import SSF.OS.*;
import SSF.OS.BGP4.*;
import SSF.OS.BGP4.Comm.*;
import SSF.OS.BGP4.Timing.*;
import SSF.OS.BGP4.Path.*;
import SSF.OS.BGP4.Util.*;


// ===== class SSF.OS.BGP4.Widgets.BGPKiller =============================== //
/**
 * A test class, masquerading as a ProtocolSession, for killing the BGP process
 * at a given time during the simulation.
 */
public class BGPKiller extends ProtocolSession {

  // ........................ member data .......................... //

  /** The BGPSession with which this tester is associated. */
  private BGPSession bgp;

  /** Whether or not the setup work has been done yet. */
  private boolean setup = false;

  /** The simulation time, in seconds, at which the BGP process will be
   *  killed. */
  private double killtime = -1.0;

  /** The simulation time, in seconds, at which the BGP process will be
   *  restarted.  It cannot be lower than the kill time.  A value of -1 means
   *  that the BGP process will not be restarted. */
  private double restarttime = -1.0;


  // ----- BGPKiller() ----------------------------------------------------- //
  /**
   * We must have a zero-argument, public constructor (so that
   * <code>newInstance()</code> can be used to create a new
   * <code>BGPKiller</code> instance).
   */
  public BGPKiller() {
  }

  // ----- config ---------------------------------------------------------- //
  /**
   * Set the configurable values (specified in DML file).
   *
   * @exception configException  if any of the calls to <code>find</code>
   *                             or <code>findSingle</code> throw such an
   *                             exception.
   */
  public void config(Configuration cfg) throws configException {
    super.config(cfg);

    String str;
    str = (String)cfg.findSingle("kill");
    if (str == null) {
      System.out.println("BGPKiller missing 'kill' attribute");
    } else {
      killtime = Double.valueOf(str).doubleValue();
    }

    str = (String)cfg.findSingle("restart");
    if (str != null) {
      restarttime = Double.valueOf(str).doubleValue();
    }
  }

  // ----- init ------------------------------------------------------------ //
  /**
   * Creates an SSF process which kills the local BGP process at a given time,
   * and possibly restarts at another given time not earlier than the kill
   * time.
   */
  public void init() {
    new process(inGraph()) {
        public boolean isSimple() {
          return false;
        }

        public void action() {
          if (!setup) {
            try {
              bgp = (BGPSession)inGraph().SessionForName("bgp");
            } catch (ProtocolException pex) {
              throw new Error("BGPKiller couldn't get handle to BGP");
            }
            setup = true;
          } else {
            waitFor(Net.seconds(killtime));
            bgp.die();
            if (restarttime != killtime) {
              waitFor(Net.seconds(restarttime-killtime));
            }
            if (restarttime != -1.0) {
              bgp.restart();
            }
            waitForever();
          }
        }
      };
  }

  // ----- now ------------------------------------------------------------- //
  /**
   * Returns the current simulation time.  A convenience method so that
   * functions, not just Processes, can get the current simulation time.
   *
   * @return the current simulation time
   */
  public double now() {
    return ((double)(inGraph().now()))/((double)Net.frequency);
  }

  // ----- push ------------------------------------------------------------ //
  /**
   * Handles incoming events.
   */
  public boolean push(ProtocolMessage message, ProtocolSession fromSession) {
    // there will never be any incoming events in this pseudo-ProtocolSession
    throw new Error("BGPKiller.push() called");
  }

} // end class BGPKiller
